package edu.northwestern.cbits.purplescope; import java.io.IOException; import java.io.RandomAccessFile; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.AlarmManager; import android.app.IntentService; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.BatteryManager; import android.os.Build; import android.os.Debug.MemoryInfo; import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; public class ScopeService extends IntentService { public static final String TICK = "scope_tick"; public static final String BEGIN_SAMPLING = "scope_begin_sampling"; public static final String END_SAMPLING = "scope_end_sampling"; public static final String TIMESTAMP = "timestamp"; public static final String DURATION = "duration"; public static final String SESSION_NAME = "session_name"; private static final String PURPLE_ROBOT_PACKAGE = "edu.northwestern.cbits.purple_robot_manager"; private static final String FUNF_PACKAGE = "edu.mit.media.funf.journal"; private static boolean _running = false; private static long _timestamp = 0; private static long _duration = 0; private static boolean _cpuEnabled = false; private static boolean _batteryEnabled = false; private static boolean _robotMemoryEnabled = false; private static boolean _funfMemoryEnabled = false; private static BroadcastReceiver _batteryReceiver = null; private static String _sessionName = null; public ScopeService() { super("Purple Scope"); } public ScopeService(String name) { super(name); } public static boolean isSampling() { return ScopeService._running; } @SuppressLint("NewApi") protected void onHandleIntent(Intent intent) { String action = intent.getAction(); AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); PendingIntent pi = PendingIntent.getService(this, 0, new Intent(ScopeService.TICK), PendingIntent.FLAG_UPDATE_CURRENT); if (ScopeService.TICK.equals(action)) { if (ScopeService._running) { if (ScopeService._duration > 0) { long now = System.currentTimeMillis(); long delta = (now - ScopeService._timestamp); ScopeService._duration = ScopeService._duration - delta; ScopeService._timestamp = now; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) alarms.setExact(AlarmManager.RTC_WAKEUP, now + 1000, pi); else alarms.set(AlarmManager.RTC_WAKEUP, now + 1000, pi); this.sample(); Intent broadcastIntent = new Intent(HomeActivity.UPDATE_INTERFACE); broadcastIntent.putExtra(ScopeService.TIMESTAMP, ScopeService._timestamp); broadcastIntent.putExtra(ScopeService.DURATION, ScopeService._duration); LocalBroadcastManager broadcasts = LocalBroadcastManager.getInstance(this); broadcasts.sendBroadcast(broadcastIntent); } else this.startService(new Intent(ScopeService.END_SAMPLING)); } } else if (ScopeService.BEGIN_SAMPLING.equals(action)) { if (ScopeService._running == false) { ScopeService._running = true; ScopeService._duration = intent.getLongExtra(ScopeService.DURATION, 0); ScopeService._sessionName = intent.getStringExtra(ScopeService.SESSION_NAME); ContentValues values = new ContentValues(); values.put("source", ScopeService._sessionName); values.put("recorded", System.currentTimeMillis()); values.put("value", "begin"); this.getContentResolver().insert(PerformanceContentProvider.PERFORMANCE_VALUES, values); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); if (prefs.contains(this.getString(R.string.resource_cpu))) ScopeService._cpuEnabled = true; else ScopeService._cpuEnabled = false; if (prefs.contains(this.getString(R.string.resource_battery))) ScopeService._batteryEnabled = true; else ScopeService._batteryEnabled = false; if (prefs.contains(this.getString(R.string.resource_memory_robot))) ScopeService._robotMemoryEnabled = true; else ScopeService._robotMemoryEnabled = false; if (prefs.contains(this.getString(R.string.resource_memory_funf))) ScopeService._funfMemoryEnabled = true; else ScopeService._funfMemoryEnabled = false; long now = System.currentTimeMillis(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) alarms.setExact(AlarmManager.RTC_WAKEUP, now + 1000, pi); else alarms.set(AlarmManager.RTC_WAKEUP, now + 1000, pi); ScopeService._timestamp = System.currentTimeMillis(); } } else if (ScopeService.END_SAMPLING.equals(action)) { if (ScopeService._running) { ContentValues values = new ContentValues(); values.put("source", ScopeService._sessionName); values.put("recorded", System.currentTimeMillis()); values.put("value", "end"); this.getContentResolver().insert(PerformanceContentProvider.PERFORMANCE_VALUES, values); ScopeService._running = false; ScopeService._cpuEnabled = false; ScopeService._robotMemoryEnabled = false; ScopeService._batteryEnabled = false; ScopeService._funfMemoryEnabled = false; Intent broadcastIntent = new Intent(HomeActivity.UPDATE_INTERFACE); broadcastIntent.putExtra(ScopeService.TIMESTAMP, ScopeService._timestamp); broadcastIntent.putExtra(ScopeService.DURATION, 0L); LocalBroadcastManager broadcasts = LocalBroadcastManager.getInstance(this); broadcasts.sendBroadcast(broadcastIntent); } } } private void sample() { if (ScopeService._cpuEnabled) { try { RandomAccessFile reader = new RandomAccessFile("/proc/stat", "r"); String load = reader.readLine(); String[] toks = load.split(" "); long idle1 = Long.parseLong(toks[5]); long cpu1 = Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[4]) + Long.parseLong(toks[6]) + Long.parseLong(toks[7]) + Long.parseLong(toks[8]); try { Thread.sleep(100); } catch (Exception e) { } reader.seek(0); load = reader.readLine(); reader.close(); toks = load.split(" "); long idle2 = Long.parseLong(toks[5]); long cpu2 = Long.parseLong(toks[2]) + Long.parseLong(toks[3]) + Long.parseLong(toks[4]) + Long.parseLong(toks[6]) + Long.parseLong(toks[7]) + Long.parseLong(toks[8]); float use = (float)(cpu2 - cpu1) / ((cpu2 + idle2) - (cpu1 + idle1)); ContentValues values = new ContentValues(); values.put("source", "cpu"); values.put("recorded", System.currentTimeMillis()); values.put("value", "" + use); this.getContentResolver().insert(PerformanceContentProvider.PERFORMANCE_VALUES, values); } catch (IOException e) { e.printStackTrace(); } } if (ScopeService._robotMemoryEnabled || ScopeService._funfMemoryEnabled) { ActivityManager activities = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); for (RunningAppProcessInfo proc : activities.getRunningAppProcesses()) { if (ScopeService._robotMemoryEnabled && ScopeService.PURPLE_ROBOT_PACKAGE.equals(proc.processName)) { int[] pids = { proc.pid }; MemoryInfo[] memoryStats = activities.getProcessMemoryInfo(pids); ContentValues values = new ContentValues(); values.put("source", "robot_memory_pss"); values.put("recorded", System.currentTimeMillis()); values.put("value", "" + this.totalMemory(memoryStats[0])); this.getContentResolver().insert(PerformanceContentProvider.PERFORMANCE_VALUES, values); } else if (ScopeService._funfMemoryEnabled && ScopeService.FUNF_PACKAGE.equals(proc.processName)) { int[] pids = { proc.pid }; MemoryInfo[] memoryStats = activities.getProcessMemoryInfo(pids); ContentValues values = new ContentValues(); values.put("source", "funf_memory_pss"); values.put("recorded", System.currentTimeMillis()); values.put("value", "" + this.totalMemory(memoryStats[0])); this.getContentResolver().insert(PerformanceContentProvider.PERFORMANCE_VALUES, values); } } } if (ScopeService._batteryEnabled) { if (ScopeService._batteryReceiver == null) { ScopeService._batteryReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if (ScopeService._batteryEnabled) { int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); ContentValues values = new ContentValues(); values.put("source", "battery_level"); values.put("recorded", System.currentTimeMillis()); values.put("value", "" + level); context.getContentResolver().insert(PerformanceContentProvider.PERFORMANCE_VALUES, values); } } }; this.getApplicationContext().registerReceiver(ScopeService._batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); } } else if (ScopeService._batteryReceiver != null) { this.getApplicationContext().unregisterReceiver(ScopeService._batteryReceiver); ScopeService._batteryReceiver = null; } } private int totalMemory(MemoryInfo memoryInfo) { return memoryInfo.getTotalPss(); } }